import 'dart:io';
import 'dart:developer' as developer;

class NetworkInfoHelper {
  Future<String> getIPAddress({bool preferIPv4 = true}) async {
    developer.log('getIPAddress called with preferIPv4: $preferIPv4',
        name: 'NetworkInfoHelper');

    List<String> searchOrder;
    if (preferIPv4) {
      searchOrder = [
        'vpn/ipv4',
        'vpn/ipv6',
        'wifi/ipv4',
        'wifi/ipv6',
        'cellular/ipv4',
        'cellular/ipv6'
      ];
    } else {
      searchOrder = [
        'vpn/ipv6',
        'vpn/ipv4',
        'wifi/ipv6',
        'wifi/ipv4',
        'cellular/ipv6',
        'cellular/ipv4'
      ];
    }

    final addresses = await _getIPAddresses();
    developer.log('Addresses found: $addresses', name: 'NetworkInfoHelper');

    String?
        foundIpv6Address; // Store a found IPv6 address, but don't return yet

    for (final key in searchOrder) {
      final address = addresses[key];
      developer.log('Checking key: $key, address: $address',
          name: 'NetworkInfoHelper');

      if (address != null && _isValidIPv4(address)) {
        developer.log('Found valid IPv4 address: $address',
            name: 'NetworkInfoHelper');
        return address; // Return IPv4 immediately if found
      }
      if (address != null && key.contains("ipv6") && _isValidIPv6(address)) {
        developer.log('Found valid IPv6 address: $address',
            name: 'NetworkInfoHelper');
        foundIpv6Address = address; // Store the IPv6 address
        // Don't return here! Continue searching for IPv4
      }
    }

    // If we get here, we didn't find a valid IPv4 address.
    if (foundIpv6Address != null) {
      developer.log('Returning found IPv6 address: $foundIpv6Address',
          name: 'NetworkInfoHelper');
      return foundIpv6Address; // Return IPv6 only if no IPv4 was found
    }

    developer.log('No valid IP address found, returning 0.0.0.0',
        name: 'NetworkInfoHelper');
    return '0.0.0.0';
  }

  bool _isValidIPv4(String ipAddress) {
    if (ipAddress.isEmpty) {
      return false;
    }
    final RegExp ipv4Regex = RegExp(
        r'^([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])$');
    return ipv4Regex.hasMatch(ipAddress);
  }

  bool _isValidIPv6(String ipAddress) {
    if (ipAddress.isEmpty) {
      return false;
    }
    final RegExp ipv6Regex = RegExp(r'^[0-9a-fA-F:]+$');
    return ipv6Regex.hasMatch(ipAddress);
  }

  Future<Map<String, String>> _getIPAddresses() async {
    final Map<String, String> addresses = {};

    try {
      final interfaces = await NetworkInterface.list();
      developer.log('Network interfaces found: ${interfaces.length}',
          name: 'NetworkInfoHelper');

      for (var interface in interfaces) {
        developer.log(
            'Interface: ${interface.name}, addresses: ${interface.addresses}',
            name: 'NetworkInfoHelper');
        String type = "";

        if (interface.name.startsWith("en") ||
            interface.name.startsWith("ap") ||
            interface.name.startsWith("wlan")) {
          type = "wifi";
        } else if (interface.name.startsWith("utun") ||
            interface.name.startsWith("ipsec")) {
          // Treat ipsec as VPN
          type = "vpn";
        } else if (interface.name.startsWith("pdp_ip") ||
            interface.name.startsWith("rmnet")) {
          type = "cellular";
        } else {
          developer.log('Unknown interface type: ${interface.name}',
              name: 'NetworkInfoHelper');
        }

        for (var addr in interface.addresses) {
          String key = "";
          if (addr.type == InternetAddressType.IPv4) {
            key = "$type/ipv4";
          } else if (addr.type == InternetAddressType.IPv6) {
            key = "$type/ipv6";
          }

          if (key.isNotEmpty) {
            addresses[key] = addr.address;
          }
        }
      }
    } catch (e) {
      developer.log('Error getting IP addresses: $e',
          name: 'NetworkInfoHelper');
    }

    return addresses;
  }
}
